package com.passer.toolbox.common.core.util;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 字符串工具类
 *
 * @author hj
 */
public class StringUtils {
    /**
     * 空字符串
     */
    private static final String NULL_STR = "";

    /**
     * 下划线
     */
    private static final char SEPARATOR = '_';

    private final static Base64.Encoder ENCODER = Base64.getEncoder();

    private final static Base64.Decoder DECODER = Base64.getDecoder();

    /**
     * 获取参数不为空值
     *
     * @param value defaultValue 要判断的value
     * @return value 返回值
     */
    public static <T> T nvl(T value, T defaultValue) {
        return value != null ? value : defaultValue;
    }

    /**
     * * 判断一个Collection是否为空， 包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Collection<?> coll) {
        return isNull(coll) || coll.isEmpty();
    }

    /**
     * * 判断一个Collection是否非空，包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * * 判断一个对象数组是否为空
     *
     * @param objects 要判断的对象数组
     *                * @return true：为空 false：非空
     */
    public static boolean isEmpty(Object[] objects) {
        return isNull(objects) || (objects.length == 0);
    }

    /**
     * * 判断一个对象数组是否非空
     *
     * @param objects 要判断的对象数组
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Object[] objects) {
        return !isEmpty(objects);
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * * 判断一个字符串是否为空串
     *
     * @param str String
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(String str) {
        return isNull(str) || NULL_STR.equals(str.trim());
    }

    /**
     * * 判断一个字符串是否为非空串
     *
     * @param str String
     * @return true：非空串 false：空串
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * * 判断一个对象是否为空
     *
     * @param object Object
     * @return true：为空 false：非空
     */
    public static boolean isNull(Object object) {
        return object == null;
    }

    /**
     * * 判断一个对象是否非空
     *
     * @param object Object
     * @return true：非空 false：空
     */
    public static boolean isNotNull(Object object) {
        return !isNull(object);
    }

    /**
     * * 判断一个对象是否是数组类型（Java基本型别的数组）
     *
     * @param object 对象
     * @return true：是数组 false：不是数组
     */
    public static boolean isArray(Object object) {
        return isNotNull(object) && object.getClass().isArray();
    }

    /**
     * 去空格
     */
    public static String trim(String str) {
        return (str == null ? "" : str.trim());
    }

    /**
     * 除日期中的特殊字符，如 -、/ 等
     * @param strDate 日期字符串
     */
    public static String dateTrim(String strDate) {
        if (isEmpty(strDate)) {
            return strDate;
        }
        strDate = strDate.replace("-", "");
        strDate = strDate.replace("/", "");
        return strDate;
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @return 结果
     */
    public static String substring(final String str, int start) {
        if (str == null) {
            return NULL_STR;
        }

        if (start < 0) {
            start = str.length() + start;
        }

        if (start < 0) {
            start = 0;
        }
        if (start > str.length()) {
            return NULL_STR;
        }

        return str.substring(start);
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @param end   结束
     * @return 结果
     */
    public static String substring(final String str, int start, int end) {
        if (str == null) {
            return NULL_STR;
        }

        if (end < 0) {
            end = str.length() + end;
        }
        if (start < 0) {
            start = str.length() + start;
        }

        if (end > str.length()) {
            end = str.length();
        }

        if (start > end) {
            return NULL_STR;
        }

        if (start < 0) {
            start = 0;
        }
        if (end < 0) {
            end = 0;
        }

        return str.substring(start, end);
    }

    /**
     * 下划线转驼峰命名
     */
    public static String toUnderScoreCase(String str) {
        // 快速检查
        if (str == null || str.isEmpty()) {
            // 没必要转换
            return str;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase;
        // 当前字符是否大写
        boolean curreCharIsUpperCase;
        // 下一字符是否大写
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0) {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            } else {
                preCharIsUpperCase = false;
            }

            curreCharIsUpperCase = Character.isUpperCase(c);

            if (i < (str.length() - 1)) {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
                sb.append(SEPARATOR);
            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
                sb.append(SEPARATOR);
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb.toString();
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。
     * 如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
     * 例如：HELLO_WORLD->HelloWorld
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return name;
        } else if (!name.contains("_")) {
            // 不含下划线
            return name.toLowerCase();
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split("_");
        int i = -1;
        // 找到首个单词转小写
        while (++i < camels.length) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camels[i].isEmpty()) {
                continue;
            }
            result.append(camels[i].toLowerCase());
            break;
        }
        // 其他单词首字母大写
        while (++i < camels.length) {
            if (camels[i].isEmpty()) {
                continue;
            }
            result.append(firstLetterToUp(camels[i].toLowerCase()));
        }
        return result.toString();
    }


    /**
     * 驼峰式转下划线大写式明明
     * @param str 代转换字符串
     * @return 转换后字符串
     */
    public static String camelHumpToUnderline(String str) {
        StringBuilder sb = new StringBuilder(str.length() * 3 / 2 + 1);

        for(int i = 0; i < str.length(); ++i) {
            char c = str.charAt(i);
            if (isUppercaseAlpha(c)) {
                sb.append('_').append(toLowerAscii(c));
            } else {
                sb.append(c);
            }
        }

        return sb.charAt(0) == '_' ? sb.substring(1) : sb.toString();
    }


    /**
     * 驼峰式命名法
     * 例如：user_name->userName
     */
    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        }
        if (s.indexOf(SEPARATOR) == -1) {
            return s;
        }
        s = s.toLowerCase();
        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            if (c == SEPARATOR) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    @SuppressWarnings("unchecked")
    public static <T> T cast(Object obj) {
        return (T) obj;
    }


    public static final String INDEX_ID_SUFFIX_FORMAT = "00000000";
    private static final DecimalFormat indexIdSuffixDf = new DecimalFormat(INDEX_ID_SUFFIX_FORMAT);

    public static String addOne(String tranSeq, String prefix) {
        String oldStrValue = tranSeq.replace(prefix, "");
        Integer oldIntValue = Integer.parseInt(oldStrValue);
        oldIntValue++;

        String newStrValue = indexIdSuffixDf.format(oldIntValue);
        return prefix + newStrValue;
    }

    public static String addOne(int tranSeq, String prefix) {
        String newStrValue = indexIdSuffixDf.format(++tranSeq);
        return prefix + newStrValue;
    }

    /**
     * 给时间减一天   接受时间类型：yyyy-mm-dd的字符串
     *
     * @return
     */
    public static String minusOneDay(String time) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        //将接收的time中的年月日截取成String数组
        String[] timeStr = time.split("-");
        Calendar calendar = Calendar.getInstance();
        int year = Integer.valueOf(timeStr[0]);
        int month = Integer.valueOf(timeStr[1]);
        int day = Integer.valueOf(timeStr[2]);
        //判断time中的日期是否是该年该月的一号，如果不是就往前减一天;如果是就看情况减月份和年份
        if (day <= 1) {
            String date = null;
            //如果月份不是1月，就对月份减一；如果月份是1月，就对年份减一；
            if (month > 1) {
                month--;
                Calendar c = Calendar.getInstance();
                c.set(year, month, 0);
                Date parse = dateFormat.parse(year + "-" + month + "-" + c.get(Calendar.DAY_OF_MONTH));
                date = dateFormat.format(parse);
            } else if (month == 1) {
                year--;
                date = year + "-12-31";
            }
            return date;
        }
        //time中的日期不是该年该月的一号，直接往前减一天
        Date date = dateFormat.parse(time);
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -1);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 解码
     *
     * @param str
     */

    public static String decoderStr(String str) {
        return new String(DECODER.decode(str), StandardCharsets.UTF_8);
    }

    /**
     * 编码
     *
     * @param str
     * @return
     */
    public static String encoderStr(String str) {
        return ENCODER.encodeToString(str.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 单词首字母大写
     * @param str 待修改字符串
     * @return 修改后字符串
     */
    public static String firstLetterToUp(String str) {
        return String.valueOf(str.charAt(0)).toUpperCase() + str.substring(1);
    }

    /**
     * 字符是否为大写字母
     * @param c 字符
     * @return boolean
     */
    public static boolean isUppercaseAlpha(char c) {
        return c >= 'A' && c <= 'Z';
    }

    /**
     * 字符是否为小写字母
     * @param c 字符
     * @return boolean
     */
    public static boolean isLowercaseAlpha(char c) {
        return c >= 'a' && c <= 'z';
    }

    /**
     * 小写字母转大写
     * @param c 小写字母
     * @return 大写字母
     */
    public static char toUpperAscii(char c) {
        if (isLowercaseAlpha(c)) {
            c = (char)(c - 32);
        }
        return c;
    }

    /**
     * 大写字母转小写
     * @param c 大写字母
     * @return 小写字母
     */
    public static char toLowerAscii(char c) {
        if (isUppercaseAlpha(c)) {
            c = (char)(c + 32);
        }
        return c;
    }

    /**
     * 字符串转字节数组字符串
     * @param text 字符串
     * @param charsetName 转换编码
     * @return 字节数组字符串
     * @throws UnsupportedEncodingException 字符串转字节数组异常
     */
    public static String textToCode(String text, String charsetName) throws UnsupportedEncodingException {
        byte[] bytes = text.getBytes(charsetName);
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : bytes) {
            stringBuilder.append(b).append(",");
        }
        return stringBuilder.toString();
    }
}
